package com.zzg.demo.laboratory.deferred;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/deferredTest")
public class DeferredTestController {

    /**
     * 1、使用TomcatConfig配置将整个Tomcat设置为1个线程
     * 2、客户端同时发起4个请求到这个方法，可以看到这4个同时发起的请求是顺序被处理的，因为全局只有一个线程，所以请求时间分别为5s、10s、15s、20s
     * 可以看到系统的瓶颈就在tomcat线程数，即吞吐量很低
     * @return
     */
    @GetMapping("/get")
    public String test(){
        try {
            // Tomcat线程会在这里阻塞等待
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("收到请求");
        return "Hello, Result!";
    }

    /**
     * 1、使用TomcatConfig配置将整个Tomcat设置为1个线程，因为只有一个线程的情况下才能看出两者的区别
     * 2、客户端同时发起4个请求到这个方法，可以看到这4个请求都会在5s后同时返回结果。可以看到DeferredResult的作用就是将请求异步化，不会阻塞Tomcat的线程
     * 异步代码里面发现有阻塞的代码，则让出线程资源，使得即便只有1个线程都可以处理大量请求，即有很高的吞吐量
     * 这也是webflux、vert.x等响应式框架的实现原理。这里就是使用DeferredResult硬编码的方式实现响应式编程
     * @return
     */
    @GetMapping("/deferredGet")
    public DeferredResult<String> get() {
        DeferredResult<String> output = new DeferredResult<>(10000L);

        output.onTimeout(() -> output.setErrorResult("Request Timeout"));
        output.onError((Throwable t) -> output.setErrorResult("Error occurred"));

        System.out.println("收到请求");
        // 这里其实是使用了ForkJoinPool.commonPool()线程池发起了异步请求，然后Tomcat线程池直接返回。真正的阻塞操作是在ForkJoinPool.commonPool()线程池中执行的，所以Tomcat线程池不会阻塞，也就是说整个Tomcat服务的吞吐量不会下降
        ForkJoinPool.commonPool().submit(() -> {
            try {
                // ForkJoinPool的线程在这里阻塞等待
                Thread.sleep(5000);
                output.setResult("Hello, DeferredResult!");
            } catch (InterruptedException e) {
                output.setErrorResult(e);
            }
        });

        // Tomcat线程直接执行完毕
        return output;
    }
}
